home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Netware Super Library
/
Netware Super Library.iso
/
btrieve
/
breset
/
btc.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-24
|
32KB
|
877 lines
/* ------------------------------ BTC.CPP ------------------------------- */
/*
BTC V1.8 - The C++ Class Library for Novell's Btrieve Record Manager 5.10
1/25/94 (C) 1994 John C. Leon. All Rights Reserved.
Written with and fully tested only under Borland C++ 3.1 and Btrieve for
DOS 5.10 ONLY, with all Btrieve patches available thru the date of this
file applied.
NOTE: Programs using this class library and its related functions
should #include "btc.hpp", and be linked with BTCS.LIB (small model)
or BTCL.LIB (large model).
There is no need to include Novell's TURCBTRV.C file when using
BTC, as the universal Btrieve call is included in the BTC libraries,
and is declared in BTC.HPP.
COMPILATION NOTES: WORD ALIGNMENT MUST BE OFF!
"TREAT ENUMS AS INT" MUST BE CHECKED!
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
extern "C" { int BTRV(int, void*, void*, int*, void*, int); }
/* Misc Types */
/* ------------------------------------------------------------------------ */
typedef unsigned char byte;
enum boolean {false, true};
typedef char FNameStr[80]; //79 + null pad for a Btrieve filename
/* Btrieve KEY ATTRIBUTES */
/* ------------------------------------------------------------------------ */
enum KEY_FLAGS {
Duplicates = 1, Modifiable = 2, Binary = 4, Null = 8,
Segmented = 16, AltCol = 32, Descending = 64,
Supplemental = 128, ExtType = 256, Manual = 512
};
/* Btrieve KEY TYPES */
/* ------------------------------------------------------------------------ */
enum KEY_TYPES {
BString = 0, BInteger, BFloat, BDate, BTime, BDecimal,
BMoney, BLogical, BNumeric, BBFloat, BLString, BZString,
BUnsBinary = 14, BAutoInc
};
/* Btrieve FILE OPEN MODES */
/* ------------------------------------------------------------------------ */
enum OPEN_MODE {
Exclusive = -4, Verify, ReadOnly, Accel, Normal
};
/* Btrieve FILE FLAGS */
/* ------------------------------------------------------------------------ */
enum FILE_FLAGS {
VarLength = 1, BlankTrunc, PreAllocate = 4, DataComp = 8,
KeyOnly = 16, Free10 = 64, Free20 = 128, Free30 = 192
};
/* Btrieve OP CODES */
/* ------------------------------------------------------------------------ */
enum OP_CODE {
BOpen, BClose, BInsert, BUpdate, BDelete, BGetEqual,
BGetNext, BGetPrev, BGetGr, BGetGrEq, BGetLess, BGetLessEq,
BGetFirst, BGetLast, BCreate, BStat, BExtend, BSetDosDir,
BGetDosDir, BBegTran, BEndTran, BAbortTran, BGetPos, BGetDirect,
BStepNext, BStop, BVersion, BUnlock, BReset, BSetOwner,
BClearOwner, BCrSuppIdx, BDropSuppIdx, BStepFirst, BStepLast, BStepPrev,
BGetNextExt, BGetPrevExt, BStepNextExt, BStepPrevExt, BInsertExt,
BGetKey = 50
};
/* Owner-Name Related Types */
/* ------------------------------------------------------------------------ */
typedef char OwnerName[9]; //8 chars max plus null
enum OwnerAccess {RQ, RO, RQENC, ROENC};
/* Selected Btrieve ERROR CODES */
/* ------------------------------------------------------------------------ */
typedef enum BTC_ERR_CODES {
FileNotOpen = 3, DataBufferLength = 22,
InvalidKeyNumber = 6, RejectCount = 60,
DiffKeyNumber = 7, IncorrectDesc = 62,
InvalidPosition = 8, FilterLimit = 64,
EndofFile = 9, IncorrectFldOff = 65,
FileNotFound = 12, LostPosition = 82,
BtrieveNotLoaded = 20
};
/* Btrieve EXTENDED OPS COMP CODES/BIAS */
/* ------------------------------------------------------------------------ */
const byte
Equal = 1, UseAltColl = 32,
GreaterThan = 2, UseField = 64,
LessThan = 3, UseNoCase = 128,
NotEqual = 4,
GrOrEqual = 5,
LessOrEqual = 6;
/* Btrieve EXTENDED OPS LOGIC CONSTANTS */
/* ------------------------------------------------------------------------ */
const int NoFilter = 0;
const char LastTerm = 0, NextTermAnd = 1, NextTermOr = 2; //As chars, can't
//make an enum.
/* Other BTC-specific Constants */
/* ------------------------------------------------------------------------ */
const int
NotRequired = 0, //Dummy for BTRV calls where int not req'd.
MaxFixedRecLength = 4090, //Btrieve limits fixed rec length for std
MaxKBufferLength = 255, //files to 4090. Max key size is 255.
None = 0, Drop = 1, Retain = 2, //These 3 used in CloneFile function.
MaxExtDBufferLength = 32767, //May be used in future for ext. calls.
MaxFileSpecLength = 665,
MaxNumSegments = 24,
KeySpecSize = 16;
/* Other BTC-specific Variables */
/* ------------------------------------------------------------------------ */
int BStatus = 0, //Global Btrieve status variable.
VarNotRequired = 0; //Dummy parameter.
byte VarPosBlk[128]; //Dummy used in ops that don't pass or
//return a position block.
/* ------------------------------------------------------------------------ */
/* BTC DATA TYPES */
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
/* Data types for TRecMgr class */
/* ------------------------------------------------------------------------ */
struct TBTVersion {
int Number;
int Rev;
char Product;
};
class TBTRecMgr {
protected:
boolean BtrieveLoaded;
TBTVersion Version;
char VerString[10];
public:
TBTRecMgr();
char* GetVersion() { return VerString; };
virtual int BT( OP_CODE OpCode, int Key = 0 );
virtual ~TBTRecMgr() { };
};
/* Data types for BBase class */
/* ------------------------------------------------------------------------ */
// TACS and TAltColSeq are for alternate collating sequences
//TACS is for the actual alternate collating sequence itself
struct TACS {
byte Header; //Header always equals 0xAC
char Name[8]; //not DOS filename, but name embedded in file
byte Table[256];
};
//TAltColSeq is the class
class TAltColSeq {
public:
TACS Spec;
TAltColSeq() { };
TAltColSeq(FNameStr SpecName);
virtual ~TAltColSeq() { };
};
union TKeySpec { // Data type for a Btrieve key spec; 'sent' Keyspec
struct {
int KeyPos;
int KeyLen;
int KeyFlags;
byte NotUsed[4]; // Tho not used in a create call, these 4 bytes
byte ExtKeyType; // return number of unique recs in key after a
byte NullValue; // stat call.
byte Reserved[4];
} SKeySpec;
struct {
int Irrelevant[3]; //This struct gives ability, on return from a
unsigned long NumUnique; //stat call, to directly read the number of
} RKeySpec; //unique records for a key.
byte Entire[16];
};
struct TKeyList {
TKeySpec KeySpec;
TKeyList *Next;
};
struct SFileSpec {
unsigned int RecLen;
int PageSize;
int NumKeys;
unsigned int NumRecs[2];// an array of int, w/high int second
int FileFlags;
byte Reserved[2];
int PreAlloc; //On return from stat, this area holds UnusedPgs.
TKeySpec KeyArray[24]; //Technically, the KeyArray and AltColSpec merely
TACS AltColSpec; //allocate space in a buffer of this data type, as it is unknown
}; //it is unknown exactly how many key specs there
//will be, or whether there will be an alternate
//collating sequence.
struct RFileSpec {
byte Irrelevant[14];
unsigned int UnusedPgs; //great after a stat call; corresponds to PreAlloc
}; //field in struct SFileSpec
union TFileSpec { //full definition of a Btrieve filespec
SFileSpec FileSpec;
RFileSpec ReturnFileSpec;
byte Entire[MaxFileSpecLength];
};
class CFileSpec { //Useful in programs that use the CreateFile fcn.
public:
TFileSpec *Specs;
TKeyList *KeyList;
CFileSpec();
CFileSpec(unsigned int RecLen, int PageSize, int NumKeys,
TKeyList *AKeyList=NULL, int FileFlags=0, int PreAlloc=0);
~CFileSpec();
};
/* In base object, no buffer is allo-
cated in constructor, and the
BT function is nearly abstract.
Create a descendant class by adding
a data buffer/struct and key buffer,
and you're all set. You'll surely
also override the constructor,
destructor, and BT functions. */
class BBase {
protected:
byte PosBlk[128];
public:
TFileSpec Specs;
FNameStr BFileName;
int IsOpen;
int SpecLength;
long NumRecs;
int NumSegs;
boolean HasAltCol;
boolean IsVariableLength;
boolean HasOwner;
OwnerName Owner;
char AltColName[9]; //8 for largest name, 1 for null
int DBufferLen;
BBase() { };
BBase(FNameStr UserFileName, OPEN_MODE OpenMode=Normal, OwnerName owner="");
virtual int Open(OPEN_MODE OpenMode=Normal);
virtual int Close();
virtual int Stat();
virtual int BT(OP_CODE OpCode, int Key=0) { return 0; };
virtual ~BBase();
};
/* Data types for BFile class */
/* ------------------------------------------------------------------------ */
class BFile: public BBase {
public:
byte *DBuffer;
byte *KBuffer;
unsigned int DBufferSize;
BFile();
BFile(FNameStr UserFileName, OPEN_MODE OpenMode = Normal, OwnerName owner = "",
unsigned int dBufferSize = MaxFixedRecLength);
virtual int BT(OP_CODE OpCode, int Key = 0);
virtual int AddSuppIndex(TKeyList* KeyList, FNameStr AltColFile="");
virtual ~BFile();
BFile& operator++(); //Overload prefix operators to do step
BFile& operator++(int); //next(++) and step previous (--).
BFile& operator--(); //Overload postfix operators to do
BFile& operator--(int); //insert(++) and delete (--).
BFile& operator=(BFile& bfixed); //Overload assignment operator to
//copy data buffer to destination.
//CloneFile() needs write access to *DBuffer and *KBuffer.
friend int CloneBTFile(FNameStr CurrentFile, FNameStr NewFile, int Option,
OwnerName Owner);
};
/* ------------------------------------------------------------------------ */
/* METHOD DEFINITIONS */
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
TBTRecMgr::TBTRecMgr() {
int sizeVersion = sizeof(Version);
BtrieveLoaded =
(BTRV(BVersion, VarPosBlk, &Version, &sizeVersion, &VarNotRequired, 0)) ?
false : true;
sprintf(VerString,"%d.%d%c", Version.Number, Version.Rev, Version.Product);
}
/* The following function will not handle reset of other workstations as
written, as no true key buffer is passed. Will handle begin/end/abort
transaction, reset & stop. Would also handle version op, but is handled
by constructor anyway! */
int TBTRecMgr::BT(OP_CODE OpCode, int Key) {
return BTRV(OpCode, VarPosBlk, &VarNotRequired, &VarNotRequired,
&VarNotRequired, Key);
}
TAltColSeq::TAltColSeq(FNameStr SpecName) {
FILE *AltColSequence;
AltColSequence = fopen(SpecName, "rb");
fread(&Spec, sizeof(Spec), 1, AltColSequence); //read in the alt col seq
fclose(AltColSequence);
}
CFileSpec::CFileSpec() {
Specs = new TFileSpec;
memset(Specs->Entire, 0, sizeof(Specs->Entire)); //Very important!!
}
CFileSpec::CFileSpec(unsigned int RecLen, int PageSize, int NumKeys,
TKeyList *AKeyList, int FileFlags, int PreAlloc) {
Specs = new TFileSpec;
memset(Specs->Entire, 0, sizeof(Specs->Entire)); //Very important!!
Specs->FileSpec.RecLen = RecLen; //Assign basic Btrieve file
Specs->FileSpec.PageSize = PageSize; //characteristics.
Specs->FileSpec.NumKeys = NumKeys;
Specs->FileSpec.FileFlags = FileFlags;
Specs->FileSpec.PreAlloc = PreAlloc;
int Counter = 0;
TKeyList *Keys = KeyList = AKeyList;
if ( Keys ) {
do {
Specs->FileSpec.KeyArray[Counter].SKeySpec.KeyPos =
Keys->KeySpec.SKeySpec.KeyPos;
Specs->FileSpec.KeyArray[Counter].SKeySpec.KeyLen =
Keys->KeySpec.SKeySpec.KeyLen;
Specs->FileSpec.KeyArray[Counter].SKeySpec.KeyFlags =
Keys->KeySpec.SKeySpec.KeyFlags;
Specs->FileSpec.KeyArray[Counter].SKeySpec.ExtKeyType =
Keys->KeySpec.SKeySpec.ExtKeyType;
Counter++;
Keys = Keys->Next;
} while ( Keys );
}
}
CFileSpec::~CFileSpec() {
delete Specs; //Dispose of file specs.
if ( KeyList ) {
TKeyList *x1, *x2; //Dispose of linked list of key specs.
x1 = KeyList;
while ( x1->Next ) {
x2 = x1->Next;
delete x1;
x1 = x2;
}
delete x1;
}
}
BBase::BBase(FNameStr UserFileName, OPEN_MODE OpenMode, OwnerName owner) {
memset(&Specs.Entire, 0, sizeof(Specs.Entire));
memset(PosBlk, 0, sizeof(PosBlk));
memset(Owner, 0, sizeof(Owner));
DBufferLen = 0;
//FileBufLen is 16 for filespec + 384 for max key
//specs + 265 for an alternate collating sequence.
int FileBufLen = MaxFileSpecLength;
int KeyBufLen = 384; //Max of 24 keys * 16 bytes per key spec
HasAltCol = false; //initialize to false..reset as needed later
strcpy(AltColName, ""); //initialize to empty string..reset as needed later
HasOwner = (strlen(owner) == 0) ? false : true;
strcpy(Owner, owner);
//Now copy DOS filename into object, and assure it's null terminated.
strcpy(BFileName, UserFileName);
//Open file in specified mode.
int Status = Open(OpenMode);
if ( !Status ) { //if Open call went ok, i.e. Status = 0
Status = BTRV(BStat, PosBlk, &Specs, &FileBufLen, &KeyBufLen, 0);
if ( !Status ) { //if Stat call went OK...fill data members
/* Btrieve filespecs and key specs are now in the BBase object!
FileBufLen will have been changed to size of data buffer returned by
stat call. Save that value now. */
SpecLength = FileBufLen;
NumRecs = Specs.FileSpec.NumRecs[0] +
Specs.FileSpec.NumRecs[1] * 65536;
IsVariableLength = ( (Specs.FileSpec.FileFlags & VarLength) == VarLength ) ?
true: false;
//Count total number of key segments
NumSegs = Specs.FileSpec.NumKeys; //Initialize to # of keys. Will
//increment as needed in next
//section.
int Counter = 1, Counter1 = 0;
while (Counter <= Specs.FileSpec.NumKeys)
do {
if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & Segmented)
== Segmented) {
if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & AltCol)
== AltCol) HasAltCol = true;
NumSegs++;
Counter1++;
}
else {
if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & AltCol)
== AltCol) HasAltCol = true;
Counter++;
Counter1++;
}
} while ((Specs.FileSpec.KeyArray[Counter1-1].SKeySpec.KeyFlags & Segmented)
== Segmented);
if (HasAltCol) {
int AltColNameOffset = 16 + (16 * NumSegs) + 1;
memcpy( AltColName, &Specs.Entire[AltColNameOffset], 8 );
AltColName[8] = '\0';
}
BStatus = 0; //Stat call went OK. Data members filled now.
}
else {
BStatus = Status; //Open succeeded but stat failed. Put error code
Close(); //for bad stat in global var BStatus, close file.
}//if stat call ok
}//if file opened ok
else
BStatus = Status; //Assign error code for bad open to global var.
} //end BBase::BBase
int BBase::Open(OPEN_MODE Mode) {
int OpenStatus;
if (HasOwner) {
DBufferLen = strlen(Owner) + 1;
OpenStatus = BTRV(BOpen, PosBlk, Owner, &DBufferLen, BFileName, Mode);
}
else
OpenStatus = BTRV(BOpen, PosBlk, &VarNotRequired, &VarNotRequired, BFileName, Mode);
IsOpen = (OpenStatus == 0) ? 1 : 0;
return OpenStatus;
}
int BBase::Close() {
if (IsOpen) {
int CloseStatus = BTRV(BClose, PosBlk, &VarNotRequired, &VarNotRequired,
&VarNotRequired, NotRequired);
IsOpen = (CloseStatus == 0) ? 0 : 1;
return CloseStatus;
}
else
return 0;
}
//File must be open for this call to succeed.
int BBase:: Stat() {
memset(&Specs.Entire, 0, sizeof(Specs.Entire));
//FileBufLen is 16 for filespec + 384 for max key
//specs + 265 for an alternate collating sequence.
int FileBufLen = MaxFileSpecLength;
int KeyBufLen = 384; //Max of 24 keys * 16 bytes per key spec
HasAltCol = false; //initialize to false..reset as needed later
strcpy(AltColName, ""); //initialize to empty string..reset as needed later
BStatus = BTRV(BStat, PosBlk, &Specs, &FileBufLen, &KeyBufLen, 0);
if ( !BStatus ) { //if Stat call went OK...fill data members
/* Btrieve filespecs and key specs are now in the BBase object!
FileBufLen will have been changed to size of data buffer returned by
stat call. Save that value now. */
SpecLength = FileBufLen;
NumRecs = Specs.FileSpec.NumRecs[0] +
Specs.FileSpec.NumRecs[1] * 65536;
IsVariableLength = ( (Specs.FileSpec.FileFlags & VarLength) == VarLength ) ? true: false;
//Count total number of key segments
NumSegs = Specs.FileSpec.NumKeys; //Initialize to # of keys. Will
//increment as needed in next
//section.
int Counter = 1, Counter1 = 0;
while (Counter <= Specs.FileSpec.NumKeys)
do {
if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & Segmented) == Segmented) {
if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & AltCol) == AltCol)
HasAltCol = true;
NumSegs++;
Counter1++;
}
else {
if ((Specs.FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags & AltCol) == AltCol)
HasAltCol = true;
Counter++;
Counter1++;
}
} while ((Specs.FileSpec.KeyArray[Counter1-1].SKeySpec.KeyFlags & Segmented)
== Segmented);
if (HasAltCol) {
int AltColNameOffset = 16 + (16 * NumSegs) + 1;
memcpy( AltColName, &Specs.Entire[AltColNameOffset], 8 );
AltColName[8] = '\0';
}
}
return BStatus;
}
BBase::~BBase() {
Close();
}
BFile::BFile() {
DBuffer = 0;
KBuffer = 0;
}
BFile::BFile(FNameStr UserFileName, OPEN_MODE OpenMode, OwnerName owner,
unsigned int dBufferSize): BBase(UserFileName, OpenMode, owner) {
DBufferSize = (dBufferSize == 0) ? MaxFixedRecLength : dBufferSize;
DBuffer = new byte [DBufferSize];
if ( DBuffer ) memset(DBuffer, 0, DBufferSize);
KBuffer = new byte [MaxKBufferLength];
if ( KBuffer ) memset(KBuffer, 0, MaxKBufferLength);
}
int BFile::BT(OP_CODE OpCode, int Key) {
return BTRV(OpCode, PosBlk, DBuffer, &DBufferLen, KBuffer, Key);
}
int BFile::AddSuppIndex(TKeyList* KeyList, FNameStr AltColFile) {
int NewSegmentCount = 1;
boolean SuppIdxHasAltCol;
TKeyList* AKeyList = KeyList;
while ( AKeyList->Next ) { //Count # of segments to be in supp index.
NewSegmentCount++;
AKeyList = AKeyList->Next;
}
if ( (NewSegmentCount + NumSegs) > MaxNumSegments )
return 1;
AKeyList = KeyList;
int Offset = 0;
do {
if ( (AKeyList->KeySpec.SKeySpec.KeyFlags & AltCol) == AltCol )
SuppIdxHasAltCol = true;
memmove( DBuffer+Offset, AKeyList, KeySpecSize);
Offset += KeySpecSize;
AKeyList = AKeyList->Next;
} while (AKeyList);
if ( KeyList ) {
TKeyList *x1, *x2; //Dispose of linked list of key specs.
x1 = KeyList;
while ( x1->Next ) {
x2 = x1->Next;
delete x1;
x1 = x2;
}
delete x1;
}
DBufferLen = KeySpecSize * NewSegmentCount;
//If the supplemental index is to have an alternate collating sequence, get
//it in the data buffer, and add its size to DBufferLen parameter.
if ( strlen(AltColFile) && SuppIdxHasAltCol ) {
TAltColSeq *ACS = new TAltColSeq(AltColFile);
memcpy( DBuffer+(KeySpecSize*NewSegmentCount), &ACS->Spec, sizeof(ACS->Spec));
DBufferLen += sizeof(ACS->Spec);
delete ACS;
}
BStatus = BT(BCrSuppIdx);
return BStatus;
}
BFile::~BFile() {
if (DBuffer != 0) delete DBuffer;
if (KBuffer != 0) delete KBuffer;
}
BFile& BFile::operator++() {
DBufferLen = DBufferSize;
BT(BStepNext);
return *this;
}
BFile& BFile::operator++(int) {
BT(BInsert); //uses default key (2nd parameter) of 0 as key for positioning
return *this;
}
BFile& BFile::operator--() {
BT(BStepPrev);
return *this;
}
BFile& BFile::operator--(int) {
BT(BDelete);
return *this;
}
BFile& BFile::operator=(BFile& bfile) {
DBufferLen = bfile.DBufferLen;
memmove(DBuffer, &(*bfile.DBuffer), bfile.DBufferSize);
return *this;
}
/* ------------------------------------------------------------------------ */
/* SPECIAL BTC FUNCTIONS */
/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */
/* CreateFile() */ //See CREATE1.CPP and CREATE2.CPP for examples of usage.
/* ------------------------------------------------------------------------ */
int CreateBTFile(FNameStr UserFileName, TFileSpec* UserFileSpec,
FNameStr AltColFile="", OwnerName Owner="",
OwnerAccess Access=RQ) {
//Count total # of key segments in UserFileSpec.
boolean HasAltCol = false;
int NumSegs = UserFileSpec->FileSpec.NumKeys;
int Counter = 1, Counter1 = 0;
while (Counter <= UserFileSpec->FileSpec.NumKeys)
do {
if ((UserFileSpec->FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags
& Segmented) == Segmented) {
if ((UserFileSpec->FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags
& AltCol) == AltCol) HasAltCol = true;
NumSegs++;
Counter1++;
}
else {
if ((UserFileSpec->FileSpec.KeyArray[Counter1].SKeySpec.KeyFlags
& AltCol) == AltCol) HasAltCol = true;
Counter++;
Counter1++;
}
}
while ((UserFileSpec->FileSpec.KeyArray[Counter1-1].SKeySpec.KeyFlags & Segmented)
== Segmented);
UserFileSpec->FileSpec.Reserved[1] = 0x00;
UserFileSpec->FileSpec.Reserved[2] = 0x00;
//If an ACS was specified, get it into the filespec.
int SpecLength = 16 + (NumSegs * 16);
if ( strlen(AltColFile) && HasAltCol ) {
TAltColSeq *AltColObj = new TAltColSeq(AltColFile);
memcpy( &UserFileSpec->Entire[SpecLength],
&AltColObj->Spec, sizeof(AltColObj->Spec) );
SpecLength += sizeof(AltColObj->Spec);
delete AltColObj;
}
BStatus = BTRV(BCreate, VarPosBlk, UserFileSpec, &SpecLength, UserFileName, 0);
int ownerLength = strlen(Owner);
if (ownerLength != 0) {
BFile *NewFile = new BFile(UserFileName, Accel, "", 9);
if (!BStatus) {
if (ownerLength > 8) ownerLength = 8;
//As there is nothing but nulls in DBuffer and KBuffer, by virtue
//of the BFile constructor for object NewFile, no need to copy the
//trailing '\0' in the Owner string...it'll be there already.
memmove(NewFile->DBuffer, Owner, ownerLength);
memmove(NewFile->KBuffer, Owner, ownerLength);
//Let Btrieve's set owner op see a trailing null.
NewFile->DBufferLen = ++ownerLength;
BStatus = NewFile->BT(BSetOwner, Access);
//Next line superfluous w/new destructor for BBase
//NewFile->Close();
delete NewFile;
}
}
return BStatus;
}
/* CloneBTFile() */ //Declared as friend to BFile class.
/* ------------------------------------------------------------------------ */
//For simplicity, this function assumes the source file for the cloning op is
//closed. Calling this function when the file is open will cause the function
//to fail, probably w/code 85, so programmers beware. If the Btrieve status
//on a bad open is returned by the constructor for CurrentBFile, the CloneFile
//function will return that value.
//NOTE!!! This function goes beyond the capability of "BUTIL -CLONE" in that
// this function has flexible handling of supplemental indexes in the
//clone file (drop, retain, or make them permanent). In addition, if no
//permanent indexes use an alternate collating sequence, but one or more
//supplemental indexes DOES use one, the clone can retain the supplemental
//indexes WITH the alternate collating sequence, duplicating the file
//structure perfectly. This is something that "BUTIL -CLONE" CANNOT HANDLE!!
int CloneBTFile(FNameStr CurrentFile, FNameStr NewFile, int Option=Retain,
OwnerName Owner="") {
BBase *CurrentBFile = new BBase(CurrentFile, ReadOnly, Owner);
if (BStatus) {
delete CurrentBFile;
return BStatus;
}
CurrentBFile->Specs.FileSpec.FileFlags &= 0xFD; //clear PreAllocate bit
CurrentBFile->Specs.ReturnFileSpec.UnusedPgs = 0;
int NewSpecLength = CurrentBFile->SpecLength;
int NewNumKeys = CurrentBFile->Specs.FileSpec.NumKeys;
boolean *SuppIdxList = new boolean[24];
boolean *SuppIdxHasAltCol = new boolean[24];
memset(SuppIdxList, false, 48);
memset(SuppIdxHasAltCol, false, 48);
boolean HasSuppIdx = false, permKeyHasAltCol = false;
int NumberSuppSegs = 0, NumberSuppIdx = 0, NewOffset = 16, Counter;
TKeySpec *SuppIdx = new TKeySpec[CurrentBFile->NumSegs];
TFileSpec *NewFileSpec = new TFileSpec;
memset( NewFileSpec->Entire, 0, sizeof(*NewFileSpec) );
memcpy( NewFileSpec->Entire, &CurrentBFile->Specs, 16 );
/* In this section, determine if there are any supplemental indexes in the
source Btrieve file. If so, set boolean indicator HasSuppIdx (which
has function-wide scope) to true. For each key segment (0 to 23)
identified as supplemental, set a corresponding boolean in an array
(SuppIdxList[24]) to true. Get a count of supplemental indexes
(NumberSuppIdx), and a count of the total number of supplemental index
segments (NumberSuppSegs). Populate an array of keyspecs (SuppIdx[24])
with the specs for all supplemental index segments.*/
for ( Counter=0; Counter < CurrentBFile->NumSegs; Counter++) {
int KeyFlags = CurrentBFile->Specs.FileSpec.KeyArray[Counter].SKeySpec.KeyFlags;
if ( ((KeyFlags & AltCol) == AltCol) && ((KeyFlags & Supplemental) != Supplemental))
permKeyHasAltCol = true;
if ( (KeyFlags & Supplemental ) == Supplemental) {
if ((KeyFlags & AltCol) == AltCol)
SuppIdxHasAltCol[NumberSuppSegs] = true;
HasSuppIdx = true;
SuppIdxList[Counter] = true;
//Next line sets one structure equal to another.
SuppIdx[NumberSuppSegs] = CurrentBFile->Specs.FileSpec.KeyArray[Counter];
//Zero supplemental bit.
SuppIdx[NumberSuppSegs].SKeySpec.KeyFlags &= 0xFF7F;
NumberSuppSegs++; //increment count of supplemental segments
if ( (KeyFlags & Segmented) != Segmented) NumberSuppIdx++;
}
}
if ( ((Option==Drop) || (Option==Retain)) && HasSuppIdx ) {
int Counter1 = 0;
for (Counter=1; Counter <= CurrentBFile->Specs.FileSpec.NumKeys; Counter++) {
if ( SuppIdxList[Counter1] ) NewNumKeys--;
do {
if ( !SuppIdxList[Counter1] ) {
NewFileSpec->FileSpec.KeyArray[Counter1] =
CurrentBFile->Specs.FileSpec.KeyArray[Counter1];
NewOffset += 16;
}
else
NewSpecLength -= 16;
Counter1++;
} while
( (CurrentBFile->Specs.FileSpec.KeyArray[Counter1-1].SKeySpec.KeyFlags
& Segmented) == Segmented );
}
NewFileSpec->FileSpec.NumKeys = NewNumKeys;
if ( CurrentBFile->HasAltCol )
memmove( &NewFileSpec->Entire[NewOffset],
&CurrentBFile->Specs.Entire[ 16 + (CurrentBFile->NumSegs * 16)], 265 );
//Next line executed if source file has supplemental indexes, and if
//option chosen was to either drop or retain them.
BStatus = BTRV(BCreate, VarPosBlk, &NewFileSpec->Entire, &NewSpecLength,
NewFile, 0);
} //end if
/* If retaining the supplemental indexes AS supplemental indexes, then at
this point we're ready to add them to the newly created file. */
if ( (Option == Retain) && HasSuppIdx ) {
BFile *NewBFile = new BFile( NewFile, Accel, "", MaxFileSpecLength );
int Counter1 = 0, DBuffOffset = 0;
for ( Counter=1; Counter<=NumberSuppIdx; Counter++) {
do {
memmove( NewBFile->DBuffer+DBuffOffset, &SuppIdx[Counter1], 16 );
DBuffOffset += 16;
Counter1++;
} while ( (SuppIdx[Counter1-1].SKeySpec.KeyFlags & Segmented) == Segmented );
NewBFile->DBufferLen = Counter1 * 16;
if (SuppIdxHasAltCol[Counter1-1] && (!permKeyHasAltCol)) {
memmove(NewBFile->DBuffer+DBuffOffset,
&(CurrentBFile->Specs.Entire[CurrentBFile->SpecLength-265]), 265);
NewBFile->DBufferLen += 265;
}
BStatus = NewBFile->BT(BCrSuppIdx);
memset( NewBFile->DBuffer, 0, MaxFileSpecLength );
DBuffOffset++;
} //end for
//Next line superfluous w/new destructor for BBase.
//NewBFile->Close();
delete NewBFile;
} //end if
/* WARNING! If user program specified 'None' and there actually ARE one or
more supplemental indexes in the source file, they WILL be retained in the
target file, as permanent indexes! This can be done intentionally if
desired. */
if ( (Option==None) || ( (Option==Retain) && !HasSuppIdx ) ||
( (Option==Drop) && !HasSuppIdx ) )
BStatus = BTRV(BCreate, VarPosBlk, &CurrentBFile->Specs,
&CurrentBFile->SpecLength, NewFile, 0);
//Next line superfluous w/new destuctor for BBase
//CurrentBFile->Close();
delete NewFileSpec; //Note NewFileSpec would not have been used if
//HandleSupps parameter to this function was 'None'
delete SuppIdx;
delete SuppIdxHasAltCol;
delete SuppIdxList;
delete CurrentBFile;
return BStatus;
}
/* NewKeySpec() */
/* ------------------------------------------------------------------------ */
// NewKeySpec() below is frequently used together with CreateBTFile(). See
// CREATE1.CPP and CREATE2.CPP.
TKeyList* NewKeySpec(int KPos, int KLen, int KFlags, byte EType,
TKeyList *NextKey = 0) {
TKeyList *TheKeyList = new TKeyList;
memset(TheKeyList, 0, sizeof(*TheKeyList));
TheKeyList->KeySpec.SKeySpec.KeyPos = KPos;
TheKeyList->KeySpec.SKeySpec.KeyLen = KLen;
TheKeyList->KeySpec.SKeySpec.KeyFlags = KFlags;
TheKeyList->KeySpec.SKeySpec.ExtKeyType = EType;
TheKeyList->Next = NextKey;
return TheKeyList;
}
/* BtrieveIsLoaded() */
/* ------------------------------------------------------------------------ */
int BtrieveIsLoaded() {
TBTVersion V;
int sizeV = sizeof(V);
return ( (BTRV( BVersion, VarPosBlk, &V, &sizeV, &VarNotRequired, 0 ))
== BtrieveNotLoaded ) ? false : true;
}
//end BTC.CPP